package org.shiki.hrm.controller;

import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.shiki.hrm.config.HighlightResultMapper;
import org.shiki.hrm.doc.CourseDoc;
import org.shiki.hrm.query.CourseDocQuery;
import org.shiki.hrm.repository.CourseDocRepository;
import org.shiki.hrm.util.AjaxResult;
import org.shiki.hrm.page.PageList;
import org.shiki.hrm.vo.AggVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/courseDoc")
public class CourseDocController {
	@Autowired
	private CourseDocRepository courseDocRepository;

	@Autowired
	private ElasticsearchTemplate elasticsearchTemplate;

	@Autowired
	private HighlightResultMapper highlightResultMapper;

	@PostMapping("/add")
	@PreAuthorize("hasAuthority('courseDoc:add')")
	public AjaxResult addCourseDoc(@RequestBody CourseDoc doc){
		courseDocRepository.save(doc);
		return AjaxResult.me();
	}

	@PostMapping("/onLineCourse")
	@PreAuthorize("hasAuthority('courseDoc:onLineCourse')")
	public AjaxResult onLineCourse(@RequestBody List<CourseDoc> list){
		courseDocRepository.saveAll(list);
		return AjaxResult.me();
	}

	@PostMapping("/offLineCourse")
	@PreAuthorize("hasAuthority('courseDoc:offLineCourse')")
	public AjaxResult offLineCourse(@RequestBody List<CourseDoc> list){
		courseDocRepository.deleteAll(list);
		return AjaxResult.me();
	}

	@PostMapping("/queryCourses")
	public AjaxResult queryCourses(@RequestBody CourseDocQuery query){
		// 准备一个NativeSearchQuery
		NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
		// 指定聚合查询字段
		builder.addAggregation(AggregationBuilders.terms("tenantNameAgg").field("tenantName").order(Terms.Order.count(false)).size(20));
		builder.addAggregation(AggregationBuilders.terms("couseTypeAgg").field("courseTypeName").order(Terms.Order.count(false)).size(20));
		// 设置高亮字段
		HighlightBuilder.Field field = new HighlightBuilder.Field("name").preTags("<font style='color:red'><b>").postTags("</b></font>");
		// 添加高亮查询
		builder.withHighlightFields(field);
		// 设置关键字查询
		BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
		String keyword = query.getKeyword();
		// 判断前端是否发送了关键字
		if (!StringUtils.isEmpty(keyword)){
			MultiMatchQueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery(keyword, "name", "courseTypeName", "tenantName");
			boolQuery.must(multiMatchQuery);
		}
		// 添加根据价格区间过滤
		Float max = query.getPriceMax();
		if (max != null){
			boolQuery.filter(QueryBuilders.rangeQuery("price").lte(max));
		}
		Float min = query.getPriceMax();
		if (min != null){
			boolQuery.filter(QueryBuilders.rangeQuery("price").gte(min));
		}
		builder.withQuery(boolQuery);
		// 设置分页
		builder.withPageable(PageRequest.of(query.getPage() - 1, query.getRows()));
		// 设置排序
		// 获取排序字段
		String sortField = query.getSortField();
		// 判断前端是否有排序方式,没有就设置默认价格排序
		sortField = StringUtils.isEmpty(sortField)?"price": sortField;
		// 获取排序方式
		FieldSortBuilder sortBuilder = new FieldSortBuilder(sortField);
		String sortType = query.getSortType();
		// 判断升序或者降序
		SortOrder order = "desc".equals(sortField) ? SortOrder.DESC : SortOrder.ASC;
		// 设置排序方式
		sortBuilder.order(order);
		builder.withSort(sortBuilder);
		// 生成query对象
		NativeSearchQuery searchQuery = builder.build();
		// 查询es
//		Page<CourseDoc> page = courseDocRepository.search(searchQuery);
//		PageList<CourseDoc> list = new PageList<>(page.getTotalElements(), page.getContent());
		// 返回查询结果
		AggregatedPage<CourseDoc> page = elasticsearchTemplate.queryForPage(searchQuery, CourseDoc.class, highlightResultMapper);
		// 封装聚合查询结果
		// 封装机构名
		StringTerms tenantAgg = (StringTerms) page.getAggregation("tenantNameAgg");
		List<StringTerms.Bucket> tenantAggBuckets = tenantAgg.getBuckets();
		List<AggVo> tenantAggs = new ArrayList<>();
		tenantAggBuckets.stream().forEach(bucket -> {
			AggVo aggVo = new AggVo();
			aggVo.setName(bucket.getKeyAsString());
			aggVo.setCount(bucket.getDocCount());
			tenantAggs.add(aggVo);
		});
		// 封装课程类型
		StringTerms typeAgg = (StringTerms) page.getAggregation("couseTypeAgg");
		List<StringTerms.Bucket> typeAggBuckets = typeAgg.getBuckets();
		List<AggVo> typeAggs = new ArrayList<>();
		tenantAggBuckets.stream().forEach(bucket -> {
			AggVo aggVo = new AggVo();
			aggVo.setName(bucket.getKeyAsString());
			aggVo.setCount(bucket.getDocCount());
			typeAggs.add(aggVo);
		});
		// 封装到map,一起返回
		Map<String, List<AggVo>> map = new HashMap<>();
		map.put("tenantAggs", tenantAggs);
		map.put("typeAggs", typeAggs);
		PageList<CourseDoc> pageList = new PageList<>(page.getTotalElements(), page.getContent(), map);
		return AjaxResult.me().setResultObj(pageList);
	}

}